using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;

// ReSharper disable EventNeverSubscribedTo.Global
// ReSharper disable UnusedMember.Global
// ReSharper disable VirtualMemberNeverOverriden.Global

namespace MvcMusicStore.BI.Client.Commands
{
  public abstract class CommandCore : FrameworkElement, IDisposable
  {
    private EventHandler mCanExecuteChanged;

    protected CommandCore()
    {
      Loaded += OnLoaded;
    }

    #region Dependency properties

    public static readonly DependencyProperty WaitPanelProperty =
      DependencyProperty.Register("WaitPanel", typeof (Panel), typeof (CommandCore), null);

    public Panel WaitPanel
    {
      get { return (Panel) GetValue(WaitPanelProperty); }
      set { SetValue(WaitPanelProperty, value); }
    }

    public static readonly DependencyProperty IsExecutingProperty =
      DependencyProperty.Register("IsExecuting", typeof (bool), typeof (CommandCore), new PropertyMetadata(default(bool)));

    public bool IsExecuting
    {
      get { return (bool) GetValue(IsExecutingProperty); }
      set { SetValue(IsExecutingProperty, value); }
    }

    #endregion

    #region Properties

    public bool HasWaitPanel
    {
      get { return WaitPanel != null; }
    }

    #endregion

    #region IDisposable

    public void Dispose()
    {
      try
      {
        Dispose(true);
      }
      finally
      {
        GC.SuppressFinalize(this);
      }
    }

    ~CommandCore()
    {
      Dispose(false);
    }

    protected void Dispose(Boolean disposing)
    {
      if (disposing)
      {
        Loaded -= OnLoaded;
      }
    }

    #endregion

    #region Events

    protected void OnLoaded(object sender, RoutedEventArgs routedEventArgs)
    {
      if (DesignerProperties.GetIsInDesignMode(this)) return;
    }

    public event EventHandler<CancelEventArgs> Executing;

    public void RaiseExecuting(CancelEventArgs cancelEventArgs)
    {
      EventHandler<CancelEventArgs> handler = Executing;
      if (handler != null) handler(this, cancelEventArgs);
    }

    public event EventHandler<CommandExecutionResultEventArgs> Executed;

    public void RaiseExecuted(CommandExecutionResult commandExecutionResult)
    {
      EventHandler<CommandExecutionResultEventArgs> handler = Executed;
      if (handler != null) handler(this, new CommandExecutionResultEventArgs(commandExecutionResult));
    }

    protected virtual void OnExecuted(CommandExecutionResult commandExecutionResult)
    {
    }

    protected void InvalidateCanExecute()
    {
      if (mCanExecuteChanged != null)
      {
        mCanExecuteChanged(this, EventArgs.Empty);
      }
    }

    public event EventHandler CanExecuteChanged
    {
      add { mCanExecuteChanged += value; }
      remove { mCanExecuteChanged -= value; }
    }

    protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
    {
      base.OnPropertyChanged(e);
      InvalidateCanExecute();
    }

    #endregion

    protected void SetComplete()
    {
      OnExecutedCore(CommandExecutionResult.FromSuccess());
    }

    private void SetFailure(Exception exception)
    {
      OnExecutedCore(CommandExecutionResult.FromException(exception));
    }

    internal void OnExecutedCore(CommandExecutionResult commandExecutionResult)
    {
      try
      {
        try
        {
          OnExecuted(commandExecutionResult);
        }
        catch (Exception e)
        {
          SetFailure(e);
          RaiseExecuted(CommandExecutionResult.FromException(e));
        }
        RaiseExecuted(commandExecutionResult);
      }
      catch (Exception e)
      {
        SetFailure(e);
        RaiseExecuted(CommandExecutionResult.FromException(e));
      }
      finally
      {
        IsExecuting = false;
      }
    }

    internal bool OnExecutingCore()
    {
      var cancelEventArgs = new CancelEventArgs();
      cancelEventArgs.Cancel = !OnExecuting();
      RaiseExecuting(cancelEventArgs);
      IsExecuting = !cancelEventArgs.Cancel;
      return IsExecuting;
    }

    protected virtual bool OnExecuting()
    {
      return true;
    }

    public override string ToString()
    {
      throw new NotImplementedException();
    }

    #region Nested type: CommandExecutionResultEventArgs

    public class CommandExecutionResultEventArgs : EventArgs
    {
      private readonly CommandExecutionResult mCommandExecutionResult;

      public CommandExecutionResultEventArgs(CommandExecutionResult commandExecutionResult)
      {
        mCommandExecutionResult = commandExecutionResult;
      }

      public CommandExecutionResult CommandExecutionResult
      {
        get { return mCommandExecutionResult; }
      }
    }

    #endregion
  }
}

// ReSharper restore EventNeverSubscribedTo.Global
// ReSharper restore UnusedMember.Global
// ReSharper restore VirtualMemberNeverOverriden.Global
